import os
from contextlib import asynccontextmanager
from datetime import datetime
from typing import Type, TypeVar, Optional, List, Any, Generic

from fastapi_pagination import Page, Params
from fastapi_pagination.ext.sqlalchemy import paginate
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy.orm import sessionmaker, RelationshipProperty
from sqlmodel import select
from sqlmodel.ext.asyncio.session import AsyncSession

from app.core.models import TimestampMixin

DATABASE_URL = os.getenv("DATABASE_URL", "sqlite+aiosqlite:///./test.db")

# 创建异步引擎
async_engine = create_async_engine(DATABASE_URL, echo=True, future=True, pool_recycle=3600)

# 创建异步会话工厂
async_session = sessionmaker(bind=async_engine, class_=AsyncSession, expire_on_commit=False)


# 获取异步会话
@asynccontextmanager
async def get_async_session() -> AsyncSession:
    async with async_session() as session:
        yield session


async def fetch_first(session: AsyncSession, query) -> Any:
    result_set = await session.execute(query)
    return result_set.scalars().first()


async def fetch_all(session: AsyncSession, query) -> List[Any]:
    result_set = await session.execute(query)
    return list(result_set.scalars().all())


def dict_to_entity(data, model_class):
    entity_dict = {}
    for key, value in data.items():
        if hasattr(model_class, key):
            attr = getattr(model_class, key)
            if isinstance(attr.property, RelationshipProperty):
                related_class = attr.mapper.class_
                if attr.impl.collection:
                    if value:
                        entity_dict[key] = [dict_to_entity(item, related_class) for item in value]
                else:
                    entity_dict[key] = value
            else:
                entity_dict[key] = value
    return model_class(**entity_dict)


T = TypeVar("T")


class ActiveRecord(Generic[T]):
    @classmethod
    async def create(cls: Type[T], session: AsyncSession, **kwargs) -> T:
        instance = cls(**kwargs)
        if isinstance(instance, TimestampMixin):
            instance.created_at = datetime.now()
            instance.updated_at = instance.created_at
        session.add(instance)
        await session.commit()
        await session.refresh(instance)
        return instance

    @classmethod
    async def get(cls: Type[T], session: AsyncSession, id: int) -> Optional[T]:
        return await session.get(cls, id)

    @classmethod
    async def get_all(cls: Type[T], session: AsyncSession) -> List[T]:
        query = select(cls)
        result = await fetch_all(session, query)
        return result

    @classmethod
    async def list(cls: Type[T], session: AsyncSession, *filters) -> list[T]:
        query = select(cls)
        for filter in filters:
            query = query.filter(filter)  # 这里需要重新赋值给 query
        result = await fetch_all(session, query)
        return result

    @classmethod
    async def list_in_pages(cls: Type[T], session: AsyncSession, params: Params = Params(), *filters) -> Page:
        query = select(cls)
        for filter in filters:
            query = query.filter(filter)  # 这里需要重新赋值给 query
        result = await paginate(session, query, params=params)
        return result

    async def update(self, session: AsyncSession, **kwargs) -> None:
        for key, value in kwargs.items():
            setattr(self, key, value)
        if isinstance(self, TimestampMixin):
            self.updated_at = datetime.now()
        await session.merge(self)
        await session.commit()
        await session.refresh(self)

    async def save(self, session: AsyncSession, **kwargs) -> None:
        for key, value in kwargs.items():
            setattr(self, key, value)
        await session.merge(self)
        await session.commit()
        await session.refresh(self)

    async def delete(self, session: AsyncSession) -> None:
        await session.delete(self)
        await session.commit()
